<?php

namespace App\Http\Controllers;

use App\Events\OrderPaid;
use App\Exceptions\InvalidRequestException;
use App\Models\Order;
use Carbon\Carbon;
use Endroid\QrCode\QrCode;
use Illuminate\Http\Request;

class PaymentController extends Controller
{
    /**
     * 支付宝支付
     *
     * @param Order $order
     * @param Request $request
     * @return void
     */
    public function payByAlipay(Order $order, Request $request)
    {
        $this->authorize('own', $order);
        // 订单已支付或者已关闭
        if ($order->paid_at || $order->closed) {
            throw new InvalidRequestException('订单状态不正确');
        }

        // 调用支付宝的网页支付
        return app('alipay')->web([
            'out_trade_no' => $order->no, // 订单编号，需保证在商户端不重复
            'total_amount' => $order->total_amount, // 订单金额，单位元，支持小数点后两位
            'subject' => '支付 Shop58 的订单：' . $order->no, // 订单标题
        ]);
    }

    /**
     * 支付付宝前端回调
     *
     * @return void
     */
    public function alipayReturn(Request $request)
    {
        try {
            // 验签
            app('alipay')->verify();
        } catch (\Exception $e) {
            return view('pages.error', ['msg' => '数据不正确']);
        }

        // 真实情况下，此段代码应在notify，服务端回调内处理，此处只是为了本地调试
        if (app()->environment() !== 'production') {
            // 订单更新，内有支付完毕事件监听
            $this->testOrderUpdate($request);

        }

        return view('pages.success', ['msg' => '付款成功！']);
    }

    /**
     * 支付宝后端服务端回调通知
     *
     * @return void
     */
    public function alipayNotify()
    {
        // 校验输入参数
        $data = app('alipay')->verify();
        // 如果订单状态不是成功或者结束，则不走后续的逻辑
        // 所有交易状态：https://docs.open.alipay.com/59/103672
        if (!in_array($data->trade_staus, ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
            return app('alipay')->success();
        }

        // $data->out_trade_no 拿到订单流水号，并在数据库中查询
        $order = Order::where('no', $data->out_trade_no)->first();
        // 正常情况下，不太可能出现支付了一笔不存在的订单，这个判断只是加强系统健壮性。
        if (!$order) {
            return 'fail!';
        }
        // 若该笔订单状态已经是已支付
        if ($order->paid_at) {
            // 返回数据给支付宝
            return app('alipay')->success();
        }

        // 变更本地订单表数据
        $order->update([
            'paid_at' => Carbon::now(), // 支付时间
            'payment_method' => 'alipay', // 支付方式
            'payment_no' => $data->trade_no, // 支付宝订单号
        ]);
        // 事件通知
        $this->afterPaid($order);

        return app('alipay')->success();
    }

    /**
     * 微信扫码支付
     *
     * @param Order $order
     * @param Request $request
     * @return void
     */
    public function payByWechat(Order $order, Request $request)
    {
        $this->authorize('own', $order);
        if ($order->paid_at || $order->closed) {
            throw new InvalidRequestException('订单状态不正确');
        }

        try {
            // 微信扫码支付,scan方法内部会验签，如非真实环境此步出错，后续无法拉取二维码
            $wechatOrder = app('wechat_pay')->scan([
                'out_trade_no' => $order->no,
                'total_fee' => $order->total_amount * 100,
                'body' => '支付 Shop58 的订单：' . $order->no,
            ]);
            // 将生成的链接信息转为二维码
            $qrCode = new Qrcode($wechatOrder->code_url);
            // 将生成的二维码图片数据以字符串形式输出，并带上相应的响应类型
            return response($qrCode->writeString(), 200, ['Content-Type' => $qrCode->getContentType()]);
        } catch (\Exception $e) {
            $qrCode = new Qrcode($e->getMessage());
            // 将生成的二维码图片数据以字符串形式输出，并带上相应的响应类型
            return response($qrCode->writeString(), 200, ['Content-Type' => $qrCode->getContentType()]);
        }
    }

    /**
     * 微信服务端回调
     *
     * @return void
     */
    public function wechatNotify()
    {
        // 校验回调参数是否正确
        $data = app('wechat_pay')->verify();
        // 找到对应的订单
        $order = Order::where('no', $data->out_trade_no)->first();
        if (!$order) {
            return 'fail';
        }
        // 订单已支付
        if ($order->paid_at) {
            // 告知微信支付此订单已经处理
            return app('wechat_pay')->success();
        }

        // 将订单标记为已支付
        $order->update([
            'paid_at' => Carbon::now(),
            'payment_method' => 'wechat',
            'payment_no' => $data->transaction_id,
        ]);

        $this->afterPaid($order);

        return app('wechat_pay')->success();
    }

    /**
     * 支付宝网页端本地测试
     *
     * @param Request $request
     * @return void
     */
    protected function testOrderUpdate(Request $request)
    {
        $order = Order::where('no', $request->out_trade_no)->first();

        if ($order && !($order->closed && $order->paid_at)) {
            // 变更本地订单表数据
            $order->update([
                'paid_at' => Carbon::now(), // 支付时间
                'payment_method' => 'alipay', // 支付方式
                'payment_no' => $request->trade_no, // 支付宝订单号
            ]);
            // 事件调度，加入在监听器中加入队列
            $this->afterPaid($order);
        }

    }

    /**
     * 事件监听调度
     *
     * @param Order $order
     * @return void
     */
    protected function afterPaid(Order $order)
    {
        event(new OrderPaid($order));
    }

    
    /**
     * 微信公众号退款 服务端回调通知
     *
     * @param Request $request
     * @return void
     */
    public function wechatRefundNotify(Request $request)
    {
        // 给微信失败响应
        $failXml = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>';
        // 验签数据 （加解密内容提取...)
        $data = app('wechat_pay')->verify(null, true);
        // 未找到对应的订单号，给微信失败响应
        if (!$order = Order::where('no', $data['out_trade_no'])->first()) {
            return $failXml;
        }

        if($data['refund_status'] === 'SUCCESS')
        {
            // 退款成功，变更订单状态
            $order->update([
                'refund_status'=> Order::REFUND_STATUS_SUCCESS,
            ]);
        }else{
            // 退款失败，记录失败状态，并修改退款状态
            $extra = $order->extra;
            $extra['refund_failed_code'] = $data['refund_status'];
            $order->update([
                'refund_status' => Order::REFUND_STATUS_FAILED,
                'extra' => $extra
            ]);
        }

        // 向微信服务器响应成功信息
        return app('wechat_pay')->success();
    }

}
